package jmine.tec.datadigester.dispatcher;

import java.io.InputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;

import jmine.tec.executionlog.domain.ExecutionLog;

import org.springframework.beans.factory.DisposableBean;

import bancosys.tec.datadigester.DataDigesterController;
import bancosys.tec.datadigester.input.ResetableInputStreamFactory;
import bancosys.tec.persist.PersistenceController;
import bancosys.tec.persist.audit.AuditManager;
import bancosys.tec.persist.audit.AuditStatus;
import bancosys.tec.rtm.impl.RtmController;
import bancosys.tec.security.chinesewall.ChineseWallContext;
import bancosys.tec.security.chinesewall.ChineseWallContextHolder;

/**
 * DataDigester ThreadPool Dispatcher
 * 
 * @author vinicius
 */
public class DataDigesterThreadPoolDispatcher implements DataDigesterDispatcher, DisposableBean {

    private ExecutorService executorService;

    private DataDigesterController dataDigesterController;

    private RtmController rtmController;

    private PersistenceController persistenceController;

    private AuditManager auditManager;

    /**
     * {@inheritDoc}
     */
    public void dispatch(final String fileCode, final String fileName, final InputStream content) {

        this.executorService.submit(new Runnable() {
            public void run() {
                try {
                    DataDigesterThreadPoolDispatcher.this.persistenceController.executeTransacted(new Callable<Void>() {
                        public Void call() throws Exception {
                            return DataDigesterThreadPoolDispatcher.this.executeTransacted(fileCode, fileName, content);
                        }
                    });
                } catch (Exception e) {
                    DataDigesterThreadPoolDispatcher.this.rtmController.monitor(e);
                }
            }
        });
    }

    /**
     * Disables auditing, authorization and chinese wall for processing file
     * 
     * @param fileCode fileCode
     * @param fileName fileName
     * @param content content
     * @return null
     * @throws Exception in action execution
     */
    public Void executeTransacted(final String fileCode, final String fileName, final InputStream content) throws Exception {
        ChineseWallContext chineseWallContext = ChineseWallContextHolder.get();
        ChineseWallContextHolder.clear();
        AuditStatus auditStatus = this.auditManager.getThreadAuditStatus();

        this.auditManager.setThreadAuditStatus(AuditStatus.DISABLED);
        try {
            this.persistenceController.executeWithDisabledAuthorization(new Callable<Void>() {
                public Void call() throws Exception {
                    try {
                        final ExecutionLog log = DataDigesterThreadPoolDispatcher.this.dataDigesterController.startExecution(fileCode, fileName, content);
                        DataDigesterThreadPoolDispatcher.this.dataDigesterController.process(fileCode, fileName, null, log.getId());
                    } finally {
                        ResetableInputStreamFactory.cleanup(content);
                    }
                    return null;
                }
            });
        } catch (Exception e) {
            throw e;
        } finally {
            ChineseWallContextHolder.set(chineseWallContext);
            this.auditManager.setThreadAuditStatus(auditStatus);
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    public void destroy() throws Exception {
        this.executorService.shutdownNow();
    }

    /**
     * @param dataDigesterController the dataDigesterController to set
     */
    public void setDataDigesterController(DataDigesterController dataDigesterController) {
        this.dataDigesterController = dataDigesterController;
    }

    /**
     * @param executorService the executorService to set
     */
    public void setExecutorService(ExecutorService executorService) {
        this.executorService = executorService;
    }

    /**
     * @param rtmController the rtmController to set
     */
    public void setRtmController(RtmController rtmController) {
        this.rtmController = rtmController;
    }

    /**
     * @param persistenceController the persistenceController to set
     */
    public void setPersistenceController(PersistenceController persistenceController) {
        this.persistenceController = persistenceController;
    }

    /**
     * @param auditManager the auditManager to set
     */
    public void setAuditManager(AuditManager auditManager) {
        this.auditManager = auditManager;
    }

}
